#include "unittest.hh"
#include "fixture.hh"
#include <algorithm>
#include <iostream>

namespace k {
namespace test {

Unittest::Unittest() {
}

Unittest::~Unittest() {
    for (auto fixture : fixtureList_) {
        delete fixture;
    }
}

bool Unittest::addFixture(Fixture * fixture) {
    fixtureList_.push_back(fixture);
    return true;
}

Fixture * Unittest::getFixture(const std::string & name) {
    for (auto fixture : fixtureList_) {
        if (fixture->getName() == name) {
            return fixture;
        }
    }
    return nullptr;
}

const Unittest::FixtureList& Unittest::getAllFixture() {
    return fixtureList_;
}

void Unittest::setDebugBreak() {
    debugBreak_ = true;
}

bool Unittest::isDebugBreak() {
    return debugBreak_;
}

void Unittest::disableFixture(const std::string & name) {
    auto it = std::find_if(fixtureList_.begin(), fixtureList_.end(), [&](const Fixture* fixture) {
        return (fixture->getName() == name);
    });
    if (it == fixtureList_.end()) {
        return;
    }
    (*it)->disable();
}

void Unittest::enableFixture(const std::string & name) {
    auto it = std::find_if(fixtureList_.begin(), fixtureList_.end(), [&](const Fixture* fixture) {
        return (fixture->getName() == name);
    });
    if (it == fixtureList_.end()) {
        return;
    }
    (*it)->enable();
}

void Unittest::runAllFixture() {
    for (auto fixture : fixtureList_) {
        if (fixture->isEnable()) {
            fixture->setup();
            fixture->runAllTestcase();
            fixture->tearDown();
        }
    }
    std::cout << std::endl;
    std::size_t pass = 0;
    std::size_t fail = 0;
    for (auto fixture : fixtureList_) {
        if (fixture->isEnable()) {
            pass += fixture->getPassCases();
            fail += fixture->getFailedCases();
        }
    }
    std::cout << "    [  " << pass << " ] [ " << green << std::left << "PASS" << black << "] " << std::endl;
    std::cout << "    [  " << fail << " ] [ " << red << std::left << "FAIL" << black << "] " << std::endl;
}

void Unittest::runAllFixtureExcept(std::initializer_list<std::string> list) {
    std::size_t pass = 0;
    std::size_t fail = 0;
    for (auto fixture : fixtureList_) {
        auto it = std::find(list.begin(), list.end(), fixture->getName());
        if (it == list.end()) {
            fixture->setup();
            fixture->runAllTestcase();
            fixture->tearDown();
            pass += fixture->getPassCases();
            fail += fixture->getFailedCases();
        }
    }
    std::cout << "    [  " << pass << " ] [ " << green << std::left << "PASS" << black << "] " << std::endl;
    std::cout << "    [  " << fail << " ] [ " << red << std::left << "FAIL" << black << "] " << std::endl;
}

void Unittest::runFixture(const std::string & name, std::size_t count) {
    auto it = std::find_if(fixtureList_.begin(), fixtureList_.end(), [&](Fixture* fixture) {
        if (fixture->getName() == name) {
            return true;
        }
        return false;
    });
    if (it == fixtureList_.end()) {
        return;
    }
    for (std::size_t i = 0; i < count; i++) {
        (*it)->setup();
        (*it)->runAllTestcase();
        (*it)->tearDown();
    }
}

void Unittest::waitKeyPress() {
    std::cout << "Press any key to quit." << std::endl;
    std::getc(stdin);
}

Unittest* Unittest::unittest_ = nullptr;

}
}
